<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>SD WebUI Benchmark Data</title>
    <meta name="viewport" content="width=device-width" id="viewport">
    <meta name="keywords" content="benchmark">
    <meta name="application-name" content="SD WebUI Benchmark Data">
    <meta name="description" content="SD WebUI Benchmark Data; Author: Vladimir Mandic <https://github.com/vladmandic>">
    <meta name="theme-color" content="#000000">
    <link rel="manifest" href="manifest.webmanifest">
    <link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
    <link rel="apple-touch-icon" href="favicon.png">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/gridjs@6.0.6/dist/theme/mermaid.css">
    <!-- <link rel="stylesheet" href="benchmark.css"> -->
    <style>
      @font-face { font-family: 'Roboto'; font-display: swap; font-style: normal; font-weight: 100; src: local('Roboto'), url('roboto.ttf') }
      html { font-family: 'Roboto', 'Segoe UI'; font-size: 14px; }
      body { margin: 0; background: black; color: white; overflow: hidden; width: 100vw; height: 100vh; line-height: 1.5rem; }
      body::-webkit-scrollbar { display: none; }
      div { margin-bottom: 0.5rem; }
      a { color: #AAA; text-decoration: none; }
      th { top: -2px !important; } /* fix for gridjs header */
      input[type=search] { background-color: #333; font-size: 1.2rem; border-color: #222; color: white; margin-left: 12px; }
      ::-webkit-scrollbar { width: 12px; }
      ::-webkit-scrollbar-track { background: #555; }
      ::-webkit-scrollbar-thumb { background-color: #AAA; border-radius: 2px; border-width: 0; box-shadow: 2px 2px 3px #111111; }
      table td:nth-child(3) { background-color: #555 !important; letter-spacing: 1px; text-align: right; }
      td.gridjs-td:last-child { white-space: nowrap; }
      .gridjs-footer { background-color: unset !important; border-top: unset !important; }
      .gridjs-pagination { color: white; }
    </style>
  </head>
  <body>
    <div style="margin: 12px">
      <h1>SD WebUI Bechmark Data</h1>
      <div>
        Benchmark data is created using | <b>SD WebUI Extension <a href="https://github.com/vladmandic/sd-extension-system-info" style="color: #CE6400">System Info</a></b>
      </div>
      Last modified | <span id="modified" style="color: #CCC"></span>
      <span id="modified" style="color: #AAA"> (page is updated automatically hourly if new data is found) <a href="https://github.com/vladmandic/sd-data/actions" target="_blank"> | STATUS</a></span>
      <div>Download 
        | <a href="https://vladmandic.github.io/sd-data/pages/benchmark-data.json" style="color: #AAA" target="_blank">DATA</a></b>
        | <a href="https://vladmandic.github.io/sd-data/input/benchmark-raw.json" style="color: #AAA" target="_blank">RAW</a></b>
      </div>
      <div style="color: #CCC"><i>Note | Performance is measured as iterations per second for different batch sizes (1, 2, 4, 8 ...) and using standardized txt2img settings</i></div>
      <br>
      <div id="table"></div> 
      <div id="log" style="color: #AAA; position: absolute; bottom: 0"></div>
    </div>
    <script type="module">
      import { Grid, html } from 'https://cdn.jsdelivr.net/npm/gridjs@6.0.6/dist/gridjs.module.js'; // eslint-disable-line import/no-unresolved, node/no-missing-import, import/extensions

      const currentUrl = new URL(location.href);
      const dataUrl = 'https://vladmandic.github.io/sd-data/pages/benchmark-data.json';

      const log = (...msg) => {
        console.log('benchmark', ...msg); // eslint-disable-line no-console
        const el = document.getElementById('log');
        el.innerHTML = Array.isArray(msg) ? msg.join(' ') : msg;
        el.style.display = 'block';
        setTimeout(() => el.style.display = 'none', 2500);
      };

      async function main() {
        let data = [];
        const res = await fetch(dataUrl);
        if (res.ok) {
          data = await res.json();
          const modified = res.headers.get('last-modified');
          document.getElementById('modified').innerHTML = `${new Date(modified).toLocaleString()}`;
          log('benchmark data loaded records:', data.length);
        } else {
          log('benchmark data load failed:', res.status, res.statusText);
        }

        const text2url = (text) => text.replace(/((|http|https|ftp):\/\/[\w?=&./-;#~%-]+(?![\w\s?&./;#~%"=-]*>))/g, "<a href='$1' target='_blank'>$1</a>").replace(/(url:)/g, '').replace('updated:', '');
        const attrs = (text) => text.replace(/(\w*:\b)/g, "<span style='color: #AAA'>$1 </span>");
        const perfSort = (a, b) => {
          const a0 = a.split('/').map((v) => v.trim());
          const b0 = b.split('/').map((v) => v.trim());
          const amax = a0.reduce((acc, cur) => Math.max(acc, isNaN(cur) ? 0 : parseFloat(cur)), 0);
          const bmax = b0.reduce((acc, cur) => Math.max(acc, isNaN(cur) ? 0 : parseFloat(cur)), 0);
          if (amax > bmax) return 1;
          if (bmax > amax) return -1;
          return 0;
        };

        const grid = new Grid({
          columns: [
            { name: '', id: 'id', width: '50px', formatter: (cell) => html(`<span style="color: #CE6400">${cell}</span>`) },
            { name: 'Date', width: '130px', formatter: (cell) => `${new Date(cell).toLocaleString()}` },
            { name: 'Performance', formatter: (cell) => html(`<b>${cell.replace(/\//g, 'it/s<br>')} it/s</b>`), sort: { compare: (a, b) => perfSort(a, b) } },
            { name: 'Version', width: '260px', formatter: (cell) => html(`${text2url(cell)}`) },
            { name: 'System', width: '400px', formatter: (cell) => html(attrs(cell)) },
            { name: 'Libraries', width: '300px', formatter: (cell) => html(attrs(cell)) },
            { name: 'GPU', width: '260px', formatter: (cell) => html(`${attrs(cell.replace('device:', ''))}`) },
            { name: 'Optimizations', formatter: (cell) => html(cell.replace(/ /g, '<br>').toLowerCase()) },
            { name: 'Model', width: '260px', formatter: (cell) => html(`<span style="color: bisque">${cell.split(/\/|\\/).pop().replace(/\[/g, '<br>[')}</span>`) },
            { name: 'Username' },
            { name: 'Note', formatter: (cell) => html(`<span style="font-size: 0.9rem">${attrs(cell?.replace('device:', '') || '')}</span>`) },
          ],
          pagination: {
            limit: 200,
            summary: true,
          },
          search: {
            keyword: currentUrl.searchParams.get('keyword') || ''
          },
          sort: { multiColumn: false },
          resizable: true,
          fixedHeader: true,
          height: '75vh',
          style: {
            table: { 'line-break': 'strict' },
            th: { 'background-color': '#CE6400', color: '#000', border: '2px solid #111', padding: '12px' },
            td: { overflow: 'hidden', padding: '6px 10px', 'line-height': '1.5rem', 'background-color': '#333', color: '#FFF', border: '2px solid #111' },
          },
          data,
        });
        grid.render(document.getElementById('table'));
        grid.on('rowClick', (...args) => log('row:', args));
        grid.on('cellClick', (...args) => log('cell:', args));
      }

      window.onload = main;
  </script>
  </body>
</html>
